/*
 * Hy103Client.cpp
 *
 *  Created on: Dec 7, 2011
 *      Author: kylintse
 */

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <fcntl.h>

#include "Hy103Client.h"

///////////////////////////////////////////////////////////////////////////////
// Hy103ClientParser
Hy103ClientParser::Hy103ClientParser(Hy103Server* server,QObject* parent/*=0*/)
	: kthread(parent),m_server(server)
{
	m_source=QString("Hy103ClientParser")+m_server->interface+server->ip;

	if(m_server->interface=="eth0")
		m_ethId=0;
	else
		m_ethId=1;
}

Hy103ClientParser::~Hy103ClientParser()
{

}

void Hy103ClientParser::run()
{
	int sockfd=m_server->sockfd;
	fd_set readfd;
	struct timeval tv;
	int ret;
	qint32 recvLen=0;
	qint32 wantLen=HY103_MIN_FRAME_LEN;
	qint32 curLen=0;
	qint32 restLen=wantLen;
	qint32 itemHeadPos;
	qint32 itemNum;
	bool bHeadValid=false;

	if(!m_server->lstDevice->regiserCommandNotifyProcessor(m_source))
	{
		setStarted(false);
//		emit sigRemoteClose(m_server->ip);
		return;
	}

	setStarted(true);

	while(true)
	{
		if(needExit())
		{
			setStarted(false);
			m_server->lstDevice->unRegisterCommandNotifyProcessor(m_source);
			return;
		}

		restLen=wantLen-curLen;
		tv.tv_sec=1;
		tv.tv_usec=0;

		FD_ZERO(&readfd);
		FD_SET(sockfd,&readfd);
		ret=::select(sockfd+1,&readfd,NULL,NULL,&tv);
		switch(ret)
		{
			case -1:
			{
//				qWarning()<<"select ret = -1";
				setStarted(false);
				m_server->lstDevice->unRegisterCommandNotifyProcessor(m_source);
				::close(sockfd);
//				emit sigRemoteClose(m_server->ip);
				return;
			}

			case 0:
			{

				continue;
			}

			default:
			{
				recvLen=::read(sockfd,m_recvBuf+curLen,restLen);
				int ledEth;

//				qWarning()<<"select ret = "<<ret<<" read ret = "<<recvLen;

				if(recvLen<=0)
				{
					// A remote close
					setStarted(false);
					m_server->lstDevice->unRegisterCommandNotifyProcessor(m_source);
					::close(sockfd);
//					emit sigRemoteClose(m_server->ip);
					return;
				}

				if(m_server->interface=="eth0")
					ledEth=led_Eth0;
				else
					ledEth=led_Eth1;
				gled->flashLed(ledEth,recvLen*2);

				curLen+=recvLen;
				if(curLen>=HY103_MIN_FRAME_LEN)
				{
					if(!bHeadValid)
					{
						if(!headValid(curLen))
						{
							wantLen=HY103_MIN_FRAME_LEN;
							curLen=0;
							continue;
						}
						if(curLen<HY103_MIN_FRAME_LEN)
							continue;
					}

					bHeadValid=true;
					wantLen=analyzeDatagramLen(curLen,itemHeadPos,wantLen,itemNum);
					if(!wantLen)
					{
						wantLen=HY103_MIN_FRAME_LEN;
						curLen=0;
						bHeadValid=false;
						continue;
					}

					if(curLen<wantLen)
						continue;

					processFrame(curLen);
					wantLen=HY103_MIN_FRAME_LEN;
					curLen=0;
					bHeadValid=false;
				}
				break;
			}
		}
	}
}

void Hy103ClientParser::processFrame(qint32 frameLen)
{
	ParamHy103Cpu* hy103Cpu;
	quint8 notifyFinish;
	quint8 cpuNum=m_recvBuf[3];
	if(cpuNum==255)
	{
		processFrameLocal(frameLen);
		return;
	}
	hy103Cpu=gHy103Cpu.value(m_recvBuf[3]);
	if(gMprDevice&&(hy103Cpu->devId<32))
	{
		if(!m_server->lstDevice->putCommand(m_source,m_ethId,m_server->type,hy103Cpu->devId,
				QByteArray(m_recvBuf,frameLen),true,2000))
		{
			glog->writeLog(llError,"Hy103ClientParser::processFrame",
					QString("Put command failed"));
			return;
		}

//		qWarning()<<"Start waiting for notify";

		QByteArray dataNotify;

		while(true)
		{
			if(!m_server->lstDevice->getCommandNotify(m_source,hy103Cpu->devId,dataNotify,
							1000,notifyFinish))
				break;

			m_server->lockDatagram.lock();
			m_server->datagrams.enqueue(dataNotify);
			m_server->lockDatagram.unlock();
			m_server->semDatagram->release(1);
			if(notifyFinish)
				break;
		}
	}
}

void Hy103ClientParser::processFrameLocal(quint32 frameLen)
{
	quint8 asduType=m_recvBuf[0];

	switch(asduType)
	{
		case ASDU_10:
			processFrameAsdu10(frameLen);
			break;

		case ASDU_20:
			processFrameAsdu20(frameLen);
			break;

		case ASDU_21:
			processFrameAsdu21(frameLen);
			break;

		default:
			break;
	}
}

void Hy103ClientParser::processFrameAsdu10(quint32 frameLen)
{
	quint8 group=m_recvBuf[8];

	switch(group)
	{
		case 0x1F:
			processFrameWriteChnnlCoff(frameLen);
			break;

		default:
			break;
	}
}

void Hy103ClientParser::processFrameAsdu20(quint32 frameLen)
{
	quint8 inf=m_recvBuf[5];

	switch(inf)
	{
		case 2:
			processFrameReadDevDesc(frameLen);
			break;

		case 11:				// read coefficient
			processFrameReadChnnlCoff(frameLen);
			break;

		case 13:				// save coefficient
			processFrameSaveChnnlCoff(frameLen);
			break;

		default:
			break;
	}
}

void Hy103ClientParser::processFrameAsdu21(quint32 frameLen)
{
	quint8 inf=m_recvBuf[5];

	switch(inf)
	{
		case 0xF1:
			processFrameReadAllItemInGrp(frameLen);
			break;

		case 0xF5:
		{
			QByteArray data;
			data.append(0x0A);
			data.append(0x81);
			data.append(42);
			data.append(m_recvBuf[3]);
			data.append(0xFE);
			data.append(0xF5);
			data.append((char)0x00);
			sendReply(data);
			break;
		}

		default:
			break;
	}
}

void Hy103ClientParser::processFrameReadAllItemInGrp(quint32 frameLen)
{
	quint32 kod=m_recvBuf[10];

	switch(kod)
	{
		case 0x0A:
			processFrameReadDesc(frameLen);
			break;

		case 0x01:
			processFrameReadValue(frameLen);
			break;

		case 0x03:
			processFrameReadRange(frameLen);
			break;

		case 0x05:
			processFrameReadPrecision(frameLen);
			break;

		case 0x09:
			processFrameReadDimension(frameLen);
			break;

		default:
			break;
	}
}

void Hy103ClientParser::processFrameReadDesc(quint32 frameLen)
{
	QByteArray data;
	QByteArray baTmp;

	data.append(m_recvBuf,7);
	data[0]=0x0A;

	QStringList* plstDesc;

	if(m_recvBuf[3]==255)
	{
		switch(m_recvBuf[8])
		{
			case 0x1F:
				plstDesc=&(gbattery.lstChnnlDesc);
				break;

			case 0x07:
				plstDesc=&(gbattery.lstMesureChnnlDesc);
				break;

			case 0x08:
				plstDesc=&(gbattery.lstAlarmDesc);
				break;

			default:
				return;
		}

		data.append(plstDesc->size());

		for(int i=0;i<plstDesc->size();i++)
		{
			data.append(m_recvBuf[8]);
			data.append(i+1);
			data.append(0x0A);
			data.append(1);
			baTmp=plstDesc->at(i).toLocal8Bit();
			data.append(baTmp.size());
			data.append(1);
			data.append(baTmp);
		}
		sendReply(data);
	}
}

void Hy103ClientParser::processFrameReadRange(quint32 frameLen)
{
	QByteArray data;
	float fdata;

	data.append(m_recvBuf,7);
	data[0]=0x0A;

	if(m_recvBuf[3]==255)
	{
		if(m_recvBuf[8]!=0x1F)
			return;

		data.append(gbattery.lstChnnlRange.size());

		for(int i=0;i<gbattery.lstChnnlRange.size();i++)
		{
			data.append(m_recvBuf[8]);
			data.append(i+1);
			data.append(3);
			data.append(6);
			data.append(4);
			data.append(3);

			fdata=gbattery.lstChnnlRange.at(i).minValue;
			data.append(*((quint8*)&fdata+0));
			data.append(*((quint8*)&fdata+1));
			data.append(*((quint8*)&fdata+2));
			data.append(*((quint8*)&fdata+3));

			fdata=gbattery.lstChnnlRange.at(i).maxValue;
			data.append(*((quint8*)&fdata+0));
			data.append(*((quint8*)&fdata+1));
			data.append(*((quint8*)&fdata+2));
			data.append(*((quint8*)&fdata+3));

			fdata=gbattery.lstChnnlRange.at(i).valueStep;
			data.append(*((quint8*)&fdata+0));
			data.append(*((quint8*)&fdata+1));
			data.append(*((quint8*)&fdata+2));
			data.append(*((quint8*)&fdata+3));
		}

		sendReply(data);
	}
}

void Hy103ClientParser::processFrameReadPrecision(quint32 frameLen)
{
	QByteArray data;

	data.append(m_recvBuf,7);
	data[0]=0x0A;

	if(m_recvBuf[3]==255)
	{
		if(m_recvBuf[8]!=0x1F)
			return;

		data.append(gbattery.lstChnnlPrecision.size());
		for(int i=0;i<gbattery.lstChnnlPrecision.size();i++)
		{
			data.append(m_recvBuf[8]);
			data.append(i+1);
			data.append(5);
			data.append(3);
			data.append(1);
			data.append(2);
			data.append(gbattery.lstChnnlPrecision.at(i).intDigits);
			data.append(gbattery.lstChnnlPrecision.at(i).decimalDigits);
		}

		sendReply(data);
	}
}

void Hy103ClientParser::processFrameReadDimension(quint32 frameLen)
{
	QByteArray data;
	QByteArray baTmp;

	data.append(m_recvBuf,7);
	data[0]=0x0A;

	QStringList* plstDesc;

	if(m_recvBuf[3]==255)
	{
		if(m_recvBuf[8]!=0x1F)
			return;

		plstDesc=&(gbattery.lstChnnlDimension);

		data.append(plstDesc->size());
		for(int i=0;i<plstDesc->size();i++)
		{
			data.append(m_recvBuf[8]);
			data.append(i+1);
			data.append(9);
			data.append(1);
			baTmp=plstDesc->at(i).toLocal8Bit();
			data.append(baTmp.size());
			data.append(1);
			data.append(baTmp);
		}

		sendReply(data);
	}
}

void Hy103ClientParser::processFrameReadValue(quint32 frameLen)
{

}

void Hy103ClientParser::processFrameReadDevDesc(quint32 frameLen)
{
	QByteArray data;
	QByteArray baTmp;

	data.append(m_recvBuf,7);

	quint8 cpuNum=m_recvBuf[3];

	data[0]=0x05;
	data[6]=0x03;

	baTmp=gbattery.desc.toLocal8Bit();

	data.append(baTmp);
	data.append((char)0);
	data.append((char)0);
	data.append((char)0);
	data.append(1);

	sendReply(data);
}

void Hy103ClientParser::processFrameReadChnnlCoff(quint32 frameLen)
{
	QByteArray data;

	data.append(m_recvBuf,8);

	quint8 cpuNum=m_recvBuf[3];

	gbattery.lock.lock();

	gbattery.chnnlCofWrite=0;

	gbattery.lock.unlock();

	if(cpuNum==255)
	{
		data.append(0x01);
		data.append(0x01);
		data.append(0x01);
		data.append(0x01);

		// Adjust status,two bytes for one channel
		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		data.append(char(0));
		data.append(char(0));

		// Channel coefficient,two bytes for each channel
		/*data.append(gbattery.volMol1Cof&0xFF);
		data.append((gbattery.volMol1Cof>>8)&0xFF);

		data.append(gbattery.volMol2Cof&0xFF);
		data.append((gbattery.volMol2Cof>>8)&0xFF);

		data.append(gbattery.volMol3Cof&0xFF);
		data.append((gbattery.volMol3Cof>>8)&0xFF);

		data.append(gbattery.volMol4Cof&0xFF);
		data.append((gbattery.volMol4Cof>>8)&0xFF);

		data.append(gbattery.volMol5Cof&0xFF);
		data.append((gbattery.volMol5Cof>>8)&0xFF);

		data.append(gbattery.volMol6Cof&0xFF);
		data.append((gbattery.volMol6Cof>>8)&0xFF);

		data.append(gbattery.volMol7Cof&0xFF);
		data.append((gbattery.volMol7Cof>>8)&0xFF);

		data.append(gbattery.volMol8Cof&0xFF);
		data.append((gbattery.volMol8Cof>>8)&0xFF);

		data.append(gbattery.volMol9Cof&0xFF);
		data.append((gbattery.volMol9Cof>>8)&0xFF);

		data.append(gbattery.volMol10Cof&0xFF);
		data.append((gbattery.volMol10Cof>>8)&0xFF);

		data.append(gbattery.volMol11Cof&0xFF);
		data.append((gbattery.volMol11Cof>>8)&0xFF);

		data.append(gbattery.volMol12Cof&0xFF);
		data.append((gbattery.volMol12Cof>>8)&0xFF);

		data.append(gbattery.curCof0&0xFF);
		data.append((gbattery.curCof0>>8)&0xFF);

		data.append(gbattery.curCof1&0xFF);
		data.append((gbattery.curCof1>>8)&0xFF);

		data.append(gbattery.tempCof0&0xFF);
		data.append((gbattery.tempCof0>>8)&0xFF);

		data.append(gbattery.tempCof1&0xFF);
		data.append((gbattery.tempCof1>>8)&0xFF);*/

		quint16 coff;

		for(int i=0;i<gbattery.lstChnnlCof.size();i++)
		{
			coff=gbattery.lstChnnlCof.at(i);
			data.append(coff&0xff);
			data.append((coff>>8)&0xff);
		}

		sendReply(data);
	}

}

void Hy103ClientParser::processFrameWriteChnnlCoff(quint32 frameLen)
{
	quint8 cpuNum,inf;
	cpuNum=m_recvBuf[3];
	inf=m_recvBuf[5];
	quint16 coff;

	QByteArray data;

	if(cpuNum==255)
	{
		if(inf==0xF9)
		{
			m_recvBuf[2]=44;
			data.append(m_recvBuf,frameLen);
			sendReply(data);
		}
		else if(inf==0xFA)
		{
			gbattery.lock.lock();
			gbattery.chnnlCofWrite=0x02;
			quint8 count=m_recvBuf[7]&0x3F;
			for(int i=0;i<count;i++)
			{
				coff=(quint8)m_recvBuf[14+i*8]+
						((quint8)m_recvBuf[15+i*8])*0x100;
				gbattery.lstChnnlCof[i]=coff;
			}
			gbattery.lock.unlock();
			m_recvBuf[2]=40;
			data.append(m_recvBuf,frameLen);
			sendReply(data);
		}
	}
}

void Hy103ClientParser::processFrameSaveChnnlCoff(quint32)
{
	quint8 cpuNum;
	cpuNum=m_recvBuf[3];

	QByteArray data;

	if(cpuNum==255)
	{
		gbattery.lock.lock();
		gbattery.chnnlCofWrite=1;
		gbattery.lock.unlock();
		data.append(m_recvBuf,8);
		sendReply(data);
	}
}

bool Hy103ClientParser::headValid(qint32& len)
{
	bool ret=false;
	char* pdata=m_recvBuf;
	for(int i=0;i<len-1;i++)
	{
		if(pdata[0]==1||
			pdata[0]==5||
			pdata[0]==6||
			pdata[0]==7||
			pdata[0]==10||
			pdata[0]==20||
			pdata[0]==21||
			pdata[0]==23||
			pdata[0]==24||
			pdata[0]==25||
			pdata[0]==26||
			pdata[0]==27||
			pdata[0]==28||
			pdata[0]==29||
			pdata[0]==30||
			pdata[0]==31||
			pdata[0]==200||
			pdata[0]==201)
		{
			if(pdata[1]==0x81)
			{
				ret=true;
				if(pdata!=m_recvBuf)
				{
					len-=(pdata-m_recvBuf);
					memmove(m_recvBuf,pdata,len);
				}
				break;
			}
		}
		pdata++;
	}

	return ret;
}

qint32 Hy103ClientParser::analyzeDatagramLen(qint32 curLen,qint32& itemHeadPos,
		qint32 wantLen,	qint32& itemNum)
{
	quint8 ucInf;
	qint32 dataLen=0;
	quint8 asduType=m_recvBuf[0];

	switch(asduType)
	{
		case 5:
			dataLen=19;
			break;

		case 6:
			dataLen=13;
			break;

		case 7:
			dataLen=7;
			break;

		case 20:
			dataLen=8;
			break;

		case 24:
			dataLen=11;
			break;

		case 25:
			dataLen=11;
			break;

		case 200:
			dataLen=38;
			break;

		case 201:
			dataLen=14;
			break;

		case 21:
			dataLen=calcAsdu21Len(curLen,itemHeadPos,wantLen,itemNum);
			break;

		case 10:
		{
			ucInf=m_recvBuf[5];
			switch(ucInf)
			{
				case 0xF9:
				case 0xFA:
				case 0xFB:
					dataLen=calcAsdu10Len(curLen,itemHeadPos,wantLen,itemNum);
					break;

				default:
					dataLen=0;
					break;
			}
			break;
		}

		default:
			dataLen=0;
			break;
	}

	return dataLen;
}

qint32 Hy103ClientParser::calcAsdu21Len(qint32 curLen,qint32& itemHeadPos,
			qint32,qint32& itemNum)
{
	qint32 totalItem=0;
	qint32 minLen=11;

	if(curLen<minLen)
	{
		itemNum=0;
		itemHeadPos=8;
		return minLen;
	}

	totalItem=m_recvBuf[7];
	return totalItem*3+8;
}

qint32 Hy103ClientParser::calcAsdu10Len(qint32 curLen,qint32& itemHeadPos,
			qint32 wantLen,qint32& itemNum)
{
	qint32 dataLen=0;
	qint32 totalItem;
	quint8 genHead=6;
	char* pdata;
	qint32 minLen,allLen;

	minLen=14;
	if(curLen<minLen)
	{
		itemNum=0;
		itemHeadPos=8;
		return minLen;
	}

	dataLen=wantLen;
	totalItem=m_recvBuf[7]&0x3F;
	if(curLen<wantLen)
		return dataLen;
	else
	{
		pdata=m_recvBuf+itemHeadPos;
		allLen=itemHeadPos+genHead+pdata[4]*pdata[5];
		if(curLen==(itemHeadPos+genHead))
		{
			dataLen=allLen;
		}
		else if(curLen==allLen)
		{
			itemNum++;
			if(itemNum<totalItem)
			{
				itemHeadPos=curLen;
				dataLen=curLen+genHead;
			}
		}
		else
			dataLen=0;

		return dataLen;
	}
}

void Hy103ClientParser::sendReply(QByteArray &data)
{
	m_server->lockDatagram.lock();
	m_server->datagrams.append(data);
	m_server->lockDatagram.unlock();
	m_server->semDatagram->release(1);
}

///////////////////////////////////////////////////////////////////////////////
// Hy103ClientSender
Hy103ClientSender::Hy103ClientSender(Hy103Server* server,QObject* parent/*=0*/)
	: kthread(parent),m_server(server)
{

}

Hy103ClientSender::~Hy103ClientSender()
{

}

void Hy103ClientSender::run()
{
	setStarted(true);
	int sendLen;

	while(true)
	{
		if(needExit())
		{
			break;
		}

		if(m_server->semDatagram->tryAcquire(1,1000))
		{
			m_server->lockDatagram.lock();
			QByteArray data=m_server->datagrams.dequeue();
			m_server->lockDatagram.unlock();
			sendLen=::send(m_server->sockfd,data.data(),data.size(),0);

			if(sendLen<=0)
			{
				setStarted(false);
				return;
			}

			int ledEth;
			if(m_server->interface=="eth0")
				ledEth=led_Eth0;
			else
				ledEth=led_Eth1;
			gled->flashLed(ledEth,data.size()*2);
		}
	}
}

///////////////////////////////////////////////////////////////////////////////
// Hy103ClientMaker
Hy103ClientMaker::Hy103ClientMaker(Hy103Server* server,QObject* parent)
	: kthread(parent),m_server(server)
{
	m_rii=0;
}

Hy103ClientMaker::~Hy103ClientMaker()
{

}

void Hy103ClientMaker::run()
{
	/*QTimer* timerAi=new QTimer;
	QTimer* timerDi=new QTimer;
	QTimer* timerPi=new QTimer;

	connect(timerAi,SIGNAL(timeout()),this,SLOT(makeAiTransmit()));
	connect(timerDi,SIGNAL(timeout()),this,SLOT(makeDiTransmit()));
	connect(timerPi,SIGNAL(timeout()),this,SLOT(makePiTransmit()));

	timerAi->start(3000);
	timerDi->start(10000);
	timerPi->start(120000);

	exec();

	timerAi->stop();
	timerDi->stop();
	timerPi->stop();

	delete timerAi;
	delete timerDi;
	delete timerPi;*/

	setStarted(true);
	quint32 count=0;

	while(true)
	{
		if(needExit())
		{
			setStarted(false);
			break;
		}

		count++;

		if(!(count%3))
			makeAiTransmit();

		if(!(count%10))
			makeDiTransmit();

		if(!(count%60))
			makePiTransmit();

		sleep(1);
	}
}

void Hy103ClientMaker::makeAiTransmit()
{
	QByteArray data;

	data.clear();

	data.append(ASDU_10);
	data.append(VSQ_COMM);
	data.append(COT_REPEAT);
	data.append(255);
	data.append(FUN_GEN);
	data.append(INF_READ_SINGLE_VAL);
	data.append(m_rii++);
	data.append(16);

	quint8 itemNum=1;
	quint16 value;
	qint32 valueTemp;

	// voltage max value = 20V
	// current max value = 10A
	// temperature max value = 100
	// capacity max value =30
	//voltage
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.voltage;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//current
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	valueTemp=gbattery.current;
	if(value>=0)
		value=valueTemp*32767/(1000*10);
	else
		value=((quint16)(~(qAbs(valueTemp)*32767/(1000*10))+1)|0x8000);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Average temperature
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	valueTemp=gbattery.tempAvg;
	if(value>=0)
			value=valueTemp*32767/(1000*10);
		else
			value=((quint16)(~(qAbs(valueTemp)*32767/(1000*100))+1)|0x8000);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Remain capacity
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.capRemain;
	value=value*32767/(1000*30);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 1
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol1;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 2
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol2;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 3
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol3;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 4
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol4;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 5
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol5;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 6
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol6;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 7
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol7;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 8
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol8;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 9
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol9;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 10
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol10;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 11
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol11;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	//Voltage of module 12
	data.append(LAN_GRP_REMOTE_MEA);
	data.append(itemNum++);
	data.append(KOD_ACTUAL_VAL);
	data.append(DATATYPE_CHARACT);
	data.append(2);
	data.append(1);
	value=gbattery.volMol12;
	value=value*32767/(1000*20);
	value=value>>3;
	data.append(value&0xFF);
	data.append(value>>8);

	m_server->lockDatagram.lock();
	m_server->datagrams.append(data);
	m_server->lockDatagram.unlock();
	m_server->semDatagram->release(1);
}

void Hy103ClientMaker::makeDiTransmit()
{
	QByteArray data;

	data.clear();

	data.append(ASDU_10);
	data.append(VSQ_COMM);
	data.append(COT_REPEAT);
	data.append(255);
	data.append(FUN_GEN);
	data.append(INF_READ_SINGLE_VAL);
	data.append(m_rii++);
	data.append(gbattery.lstDiValue.size());

	for(int i=0;i<gbattery.lstDiValue.size();i++)
	{
		data.append(LAN_GRP_SOE_DI);
		data.append(i+1);
		data.append(KOD_ACTUAL_VAL);
		data.append(DATATYPE_DPI);
		data.append(1);
		data.append(1);
		data.append(gbattery.lstDiValue.at(i));
	}

	m_server->lockDatagram.lock();
	m_server->datagrams.append(data);
	m_server->lockDatagram.unlock();
	m_server->semDatagram->release(1);
}

void Hy103ClientMaker::makePiTransmit()
{

}

///////////////////////////////////////////////////////////////////////////////
// Hy103ClientEventProcessor
Hy103ClientEventProcessor::Hy103ClientEventProcessor(Hy103Server* server,QObject* parent/*=0*/)
	: kthread(parent),m_server(server)
{
	if(m_server->interface=="eth0")
		m_id=(m_server->ip&0x0000FFFF);
	else
		m_id=((1<<16)|(m_server->ip&0x0000FFFF));

	m_processorId=QString("Hy103EventProcessor")+m_server->interface+server->ip;
}

Hy103ClientEventProcessor::~Hy103ClientEventProcessor()
{

}

void Hy103ClientEventProcessor::run()
{
	QList<quint32> lstDev;
	QMap<quint32,ParamHy103Cpu*>::const_iterator i=gHy103Cpu.constBegin();
	while(i!=gHy103Cpu.constEnd())
	{
		lstDev.append(i.value()->devId);
		i++;
	}

	m_server->lstDevice->registerEventProcessor(m_processorId,lstDev);
	setStarted(true);

	quint32 devId;
	KjEventType evType;
	qint32 code;
	quint32 timeOccur;
	QByteArray data;
	quint8 rii=0;

	while(true)
	{
		if(needExit())
			break;

		if(m_server->lstDevice->getEvent(m_processorId,devId,evType,code,timeOccur,data,1000))
		{
			switch(evType)
			{
				case ketSoe:
				{
					data.append(0x0A);
					data.append(0x81);
					data.append(0x01);
					data.append(devId);
					data.append(254);
					data.append(244);
					data.append(rii++);
					data.append(2);

					data.append(0x08);
					data.append(code);
					data.append(1);
					data.append(9);
					data.append(1);
					data.append(1);
					data.append(data.at(0)+1);
					data.append(0x18);
					data.append(code);
					data.append(1);
					data.append(18);
					data.append(6);
					data.append(1);
					data.append(data.at(0)+1);
					data.append(char(0));
					data.append(char(0));
					data.append(QDateTime::fromTime_t(timeOccur)
							.time().minute());
					data.append(QDateTime::fromTime_t(timeOccur)
							.time().hour());
					data.append(char(0));
					break;
				}

				default:
					continue;
			}
			m_server->lockDatagram.lock();
			m_server->datagrams.enqueue(data);
			m_server->lockDatagram.unlock();
			m_server->semDatagram->release(1);
			data.clear();
		}
/*
		if(gbattery.lock.tryLock(1000))
		{
			eventCount=gbattery.lstEvent.size();
			if(!eventCount)
			{
				gbattery.lock.unlock();
				continue;
			}

			data.append(0x0A);
			data.append(0x81);
			data.append(0x01);
			data.append(255);
			data.append(254);
			data.append(244);
			data.append(rii++);
			data.append(eventCount*2);
			for(int i=0;i<eventCount;i++)
			{
				subNumber=gbattery.lstEvent.at(i).code;
				data.append(0x08);
				data.append(subNumber);
				data.append(1);
				data.append(9);
				data.append(1);
				data.append(1);
				data.append(gbattery.lstDiValue.at(subNumber-1));
				data.append(0x18);
				data.append(subNumber);
				data.append(1);
				data.append(18);
				data.append(6);
				data.append(1);
				data.append(gbattery.lstDiValue.at(subNumber-1));
				data.append(char(0));
				data.append(char(0));
				data.append(QDateTime::fromTime_t(gbattery.lstEvent.
						at(i).timeOccur).time().minute());
				data.append(QDateTime::fromTime_t(gbattery.lstEvent.
						at(i).timeOccur).time().hour());
				data.append(char(0));
			}
			gbattery.lstEvent.clear();
			gbattery.lock.unlock();
			m_server->lockDatagram.lock();
			m_server->datagrams.enqueue(data);
			m_server->lockDatagram.unlock();
			m_server->semDatagram->release(1);
			data.clear();
		}*/
	}

	setStarted(false);
	m_server->lstDevice->unregisterEventProcessor(m_processorId);
}

///////////////////////////////////////////////////////////////////////////////
// MprDatagramProcessor
MprDatagramProcessor::MprDatagramProcessor(KjDeviceList* lstDevice,QObject* parent/*=0*/)
	: kthread(parent),m_lstDevice(lstDevice)
{

}

MprDatagramProcessor::~MprDatagramProcessor()
{

}

bool MprDatagramProcessor::registerHy103Sender(const QString& interface,Hy103Server* server)
{
	QMutexLocker lock(&m_lockSender);
	if(interface=="eth0")
	{
		m_lstSenderEth0.append(server);
	}
	else if(interface=="eth1")
	{
		m_lstSenderEth1.append(server);
	}
	else
		return false;

	return true;
}

bool MprDatagramProcessor::unRegisterHy103Sender(const QString& interface,quint32 ip)
{
	QList<Hy103Server*>* lstSender;

	QMutexLocker lock(&m_lockSender);
	if(interface=="eth0")
		lstSender=&m_lstSenderEth0;
	else if(interface=="eth1")
		lstSender=&m_lstSenderEth1;
	else
		return false;

	for(int i=0;i<lstSender->size();i++)
	{
		if(lstSender->at(i)->ip==ip)
		{
			lstSender->removeAt(i);
			return true;
		}
	}

	return false;
}

void MprDatagramProcessor::run()
{
	QByteArray data;
	QList<Hy103Server*>* lstSender;
	Hy103Server* server;

	qint32 watchDog=gwatchDog->registerWatchDog("MprDatagramProcessor",2000);

	setStarted(true);
	while(true)
	{
		gwatchDog->resetWatchDog(watchDog);
		if(needExit())
			break;

		if(m_lstDevice->getDatagram(data,1000))
		{
			m_lockSender.lock();
			if(data.at(0)==0)
				lstSender=&m_lstSenderEth0;
			else if(data.at(0)==1)
				lstSender=&m_lstSenderEth1;
			else if(data.at(0)==2)
			{
				for(int i=0;i<m_lstSenderEth0.size();i++)
				{
					server=m_lstSenderEth0.at(i);
					server->lockDatagram.lock();
					server->datagrams.append(data.mid(1));
					server->lockDatagram.unlock();
					server->semDatagram->release(1);
				}

				for(int i=0;i<m_lstSenderEth1.size();i++)
				{
					server=m_lstSenderEth1.at(i);
					server->lockDatagram.lock();
					server->datagrams.append(data.mid(1));
					server->lockDatagram.unlock();
					server->semDatagram->release(1);
				}
				m_lockSender.unlock();
				continue;
			}
			else
			{
				m_lockSender.unlock();
				continue;
			}

			for(int i=0;i<lstSender->size();i++)
			{
				server=lstSender->at(i);
				server->lockDatagram.lock();
				server->datagrams.append(data.mid(1));
				server->lockDatagram.unlock();
				server->semDatagram->release(1);
			}

			m_lockSender.unlock();
		}
	}

	gwatchDog->unregisterWatchDog(watchDog);
	setStarted(false);
}

///////////////////////////////////////////////////////////////////////////////
// Hy103Client
Hy103Client::Hy103Client(const QString& interface,KjDeviceList* lstDevice,
		MprDatagramProcessor* dgProcessor)
	: m_interface(interface),m_lstDevice(lstDevice),m_dgProcessor(dgProcessor)
{
	m_bRunning=false;
}

Hy103Client::~Hy103Client()
{
	close();
	m_bRunning=false;
}

bool Hy103Client::init()
{
	if(m_interface=="eth0")
	{
		m_localIp=gEthernetParm[0].ip;
		m_udpPort=UDP_PORT_ETH0;
		m_tcpPort=TCP_PORT_ETH0;
		m_watchDogId=gwatchDog->registerWatchDog("Hy103Eth0",20000);
	}
	else if(m_interface=="eth1")
	{
		m_localIp=gEthernetParm[1].ip;
		m_udpPort=UDP_PORT_ETH1;
		m_tcpPort=TCP_PORT_ETH1;
		m_watchDogId=gwatchDog->registerWatchDog("Hy103Eth1",20000);
	}
	else
		return false;

	m_udpSocket=new QUdpSocket;
	m_udpSocket->bind(QHostAddress(m_localIp),m_udpPort);
	connect(m_udpSocket,SIGNAL(readyRead()),this,SLOT(processUdpData()),
			Qt::QueuedConnection);

	m_timerHeartBeat=new QTimer;
	connect(m_timerHeartBeat,SIGNAL(timeout()),this,SLOT(timerCheckHeartBeat()),
			Qt::DirectConnection);
	m_timerHeartBeat->start(10000);
	m_bRunning=true;
	return true;
}

void Hy103Client::close()
{
	if(!m_bRunning)
		return;

	delete m_udpSocket;
	m_timerHeartBeat->stop();
	delete m_timerHeartBeat;

	QMap<quint32,Hy103Server*>::const_iterator i=m_servers.constBegin();
	Hy103Server* server;
	while(i!=m_servers.constEnd())
	{
		server=i.value();
		server->lock.lock();
		if(server->connected)
		{
			server->parser->exit();
			server->parser->wait();
			delete server->parser;

			server->maker->quit();
			server->maker->wait();
			delete server->maker;

			server->sender->exit();
			server->sender->wait();
			delete server->sender;

			server->eventProcessor->exit();
			server->eventProcessor->wait();
			delete server->eventProcessor;

			::close(server->sockfd);
			delete server->semDatagram;
			server->connected=false;
		}
		server->lock.unlock();
		delete server;
		i++;
	}

	m_servers.clear();
}

void Hy103Client::processUdpData()
{
	qint32 len;
	QByteArray data;
	QHostAddress remoteHost;
	quint32 serverIp;
	quint16 remotePort;
	struct sockaddr_in serverAddr;

//	qWarning()<<QThread::currentThreadId();

	while(m_udpSocket->hasPendingDatagrams())
	{
		len=m_udpSocket->pendingDatagramSize();
		data.resize(len);
		m_udpSocket->readDatagram(data.data(),len,&remoteHost,&remotePort);
		int ledEth;
		if(m_interface=="eth0")
			ledEth=led_Eth0;
		else
			ledEth=led_Eth1;
		gled->flashLed(ledEth,len*2);
		serverIp=remoteHost.toIPv4Address();
		if((len==41)&&(data.at(0)==0xFF))
		{
			m_lockServers.lock();
//			qWarning()<<"New connection recved";
			if(!m_servers.contains(serverIp))
			{
				// A new connection will be established
				int sockfd=::socket(AF_INET,SOCK_STREAM,0);
				int flags = fcntl(sockfd, F_GETFL, 0);
				fcntl(sockfd, F_SETFL, flags|O_NONBLOCK);
				if(sockfd<0)
				{
					m_lockServers.unlock();
					glog->writeLog(llError,"Hy103Client::processUdpData",
							"Create socket failed");
					::close(sockfd);
					return;
				}

				memset(&serverAddr,0,sizeof(serverAddr));
				serverAddr.sin_family=AF_INET;
				serverAddr.sin_port=htons(m_tcpPort);
				serverAddr.sin_addr.s_addr=htonl(serverIp);
				int ret;
				ret=::connect(sockfd,(struct sockaddr*)&serverAddr,sizeof(serverAddr));

				fd_set writefd;
				struct timeval tv;


				tv.tv_sec=5;
				tv.tv_usec=0;

				FD_ZERO(&writefd);
				FD_SET(sockfd,&writefd);
				ret=::select(sockfd+1,NULL,&writefd,NULL,&tv);
				if(!ret)
				{
					m_lockServers.unlock();
					glog->writeLog(llError,"Hy103Client::processUdpData",
							"Connect to server failed");
					::close(sockfd);
					return;
				}

				Hy103Server* server=new Hy103Server;
				server->sockfd=sockfd;
				server->ip=serverIp;

				if(data[13]=='S'&&
					data[14]=='C'&&
					data[15]=='S')
					server->type=hstScs;
				else if(data[13]=='R'&&
					data[14]=='T'&&
					data[15]=='U')
					server->type=hstRtu;
				else if(data[13]=='D'&&
					data[14]=='E'&&
					data[15]=='B')
					server->type=hstDebug;
				else if(data[13]=='P'&&
					data[14]=='R'&&
					data[15]=='T')
					server->type=hstPrt;
				else
				{
					m_lockServers.unlock();
					::close(sockfd);
					delete server;
					return;
				}

				m_servers.insert(serverIp,server);
				m_lockServers.unlock();

				server->semDatagram=new QSemaphore(0);
				server->lstDevice=m_lstDevice;
				server->interface=m_interface;
				server->heartBeatTime=QDateTime::currentDateTime();

				server->sender=new Hy103ClientSender(server);
				server->sender->start(5000);

				server->parser=new Hy103ClientParser(server);
				server->parser->start(5000);
				connect(server->parser,SIGNAL(finished()),
						this,SLOT(remoteClose()),Qt::QueuedConnection);
//				connect(server->sender,SIGNAL(finished()),
//						this,SLOT(remoteClose()),Qt::QueuedConnection);

				server->eventProcessor=new Hy103ClientEventProcessor(server);
				server->eventProcessor->start(5000);

				server->maker=new Hy103ClientMaker(server);
				server->maker->start(5000);

				m_dgProcessor->registerHy103Sender(m_interface,server);

				server->connected=true;
//				qWarning()<<"New connection established server ip = "
//						<<remoteHost.toString();
			}
			else if(data.at(1)==0x01)
			{
				adjustTime(data.mid(2,7));
				m_servers.value(serverIp)->heartBeatTime=QDateTime::currentDateTime();
				m_lockServers.unlock();
			}
			else
				m_lockServers.unlock();
		}
		else if(data.size()==9)
		{
			if(!m_servers.contains(serverIp))
				return;
			m_lockServers.lock();
			m_servers.value(serverIp)->heartBeatTime=QDateTime::currentDateTime();
			m_lockServers.unlock();
		}
	}
}

void Hy103Client::timerCheckHeartBeat()
{
	gwatchDog->resetWatchDog(m_watchDogId);
	QMap<quint32,Hy103Server*>::const_iterator i=m_servers.constBegin();
	Hy103Server* server;
	while(i!=m_servers.constEnd())
	{
		server=i.value();
		i++;
		if(server->heartBeatTime.secsTo(QDateTime::currentDateTime())>HEARTBEAT_TIMEOUT)
		{
			closeServer(server->ip);
		}
	}
}

void Hy103Client::remoteClose()
{
	Hy103ClientParser* parser=(Hy103ClientParser*)sender();

//	qWarning()<<"remoteClose";
	quint32 ip=parser->serverIp();
	closeServer(ip);
}

void Hy103Client::closeServer(quint32 ip)
{
//	qWarning()<<"Begin close server ip = "<<QHostAddress(ip).toString();
	m_lockServers.lock();
	if(!m_servers.contains(ip))
	{
		m_lockServers.unlock();
		return;
	}

	Hy103Server* server=m_servers.value(ip);
	m_servers.remove(ip);
	m_lockServers.unlock();

	server->lock.lock();
	if(server->connected)
	{
		m_dgProcessor->unRegisterHy103Sender(m_interface,server->ip);
		disconnect(server->parser,SIGNAL(finished()),this,SLOT(remoteClose()));
//		disconnect(server->sender,SIGNAL(finished()),this,SLOT(remoteClose()));
		server->parser->exit();
		server->parser->wait(5000);
		server->parser->deleteLater();

//		qWarning()<<"Parser closed";
//
//		delete server->parser;

		server->maker->exit();
		server->maker->wait(5000);
		server->maker->deleteLater();

//		qWarning()<<"Maker closed";
//
//		delete server->maker;

		server->sender->exit();
		server->sender->wait(5000);
		server->sender->deleteLater();

//		qWarning()<<"sender closed";
//
//		delete server->sender;

		server->eventProcessor->exit();
		server->eventProcessor->wait(5000);
		server->eventProcessor->deleteLater();

//		qWarning()<<"eventprocessor closed";
//
//		delete server->eventProcessor;

		::close(server->sockfd);
		delete server->semDatagram;
		server->connected=false;
	}
	server->lock.unlock();
	delete server;
//	qWarning()<<"Connection closed server ip = "
//				<<QHostAddress(ip).toString();
}

void Hy103Client::adjustTime(const QByteArray& data)
{
	quint16 year=data.at(6)+2000;
	quint8 month=data.at(5);
	quint8 day=data.at(4);
	quint8 hour=data.at(3);
	quint8 minute=data.at(2);
	quint16 sec=(((quint16)data.at(1))*0x100+(quint16)data.at(0))/1000;

	QString strCmd;
	strCmd.sprintf("date %02d%02d%02d%02d%04d.%02d",month,day,hour,minute,
			year,sec);
	::system(strCmd.toAscii().data());

}

///////////////////////////////////////////////////////////////////////////////
// Hy103ClientManager
Hy103ClientManager::Hy103ClientManager(const QString& interface,
		KjDeviceList* lstDevice,MprDatagramProcessor* dgProcessor,
		QObject* parent/*=0*/)
	: kthread(parent),m_interface(interface),m_lstDevice(lstDevice),
	  m_dgProcessor(dgProcessor)
{

}

Hy103ClientManager::~Hy103ClientManager()
{

}

void Hy103ClientManager::run()
{
	m_client=new Hy103Client(m_interface,m_lstDevice,m_dgProcessor);
	if(!m_client->init())
	{
		delete m_client;
		setStarted(false);
		return;
	}

	setStarted(true);
	exec();
	m_client->close();
	delete m_client;
}
